package com.jin.webvideo.config.filter;

import com.jin.webvideo.base.util.ObjectsUtil;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

public class GroupFilter implements Filter {
    private class InnerFilterChain implements FilterChain {
        private FilterChain nextChain;
        private Filter filter;
        protected InnerFilterChain(Filter filter, FilterChain nextChain) {
            this.filter = filter;
            this.nextChain = nextChain;
        }

        protected InnerFilterChain(Filter filter) {
            this(filter, null);
        }

        public void setNextChain(FilterChain nextChain) {
            this.nextChain = nextChain;
        }

        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse) throws IOException, ServletException {
            filter.doFilter(servletRequest, servletResponse, nextChain);
        }
    }

    private String[] excludePathPatterns;
    private InnerFilterChain firstChain;
    private InnerFilterChain lastChain;
    public GroupFilter(Filter filter) {
        this.lastChain = this.firstChain = new InnerFilterChain(filter);
        this.excludePathPatterns = ObjectsUtil.Empty.STRINGS;
    }

    public void addFilter(Filter filter) {
        InnerFilterChain next = new InnerFilterChain(filter);
        lastChain.setNextChain(next);
        lastChain = next;
    }
    public void excludePathPatterns(String... pattern) {
        this.excludePathPatterns = pattern;
    }
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        if (servletRequest instanceof HttpServletRequest request) {
            if (!match(request.getRequestURI())) {
                this.lastChain.setNextChain(filterChain);
                this.firstChain.doFilter(servletRequest, servletResponse);
                return;
            }
        }
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {
        Filter.super.destroy();
    }

    private boolean match(String path) {
        for (String p : excludePathPatterns) {
            if (matchFiltersURL(p, path)) {
                return true;
            }
        }
        return false;
    }
    protected static boolean matchFiltersURL(String testPath, String requestPath) {
        if (testPath == null) {
            return false;
        } else if (testPath.equals(requestPath)) {
            return true;
        } else if (testPath.equals("/*")) {
            return true;
        } else if (testPath.endsWith("/*")) {
            if (testPath.regionMatches(0, requestPath, 0, testPath.length() - 2)) {
                if (requestPath.length() == testPath.length() - 2) {
                    return true;
                }

                if ('/' == requestPath.charAt(testPath.length() - 2)) {
                    return true;
                }
            }

            return false;
        } else {
            if (testPath.startsWith("*.")) {
                int slash = requestPath.lastIndexOf(47);
                int period = requestPath.lastIndexOf(46);
                if (slash >= 0 && period > slash && period != requestPath.length() - 1 && requestPath.length() - period == testPath.length() - 1) {
                    return testPath.regionMatches(2, requestPath, period + 1, testPath.length() - 2);
                }
            }

            return false;
        }
    }
}
